package cn.ylyhappy.netdemo.config

import android.util.Log
import com.blankj.utilcode.util.GsonUtils
import com.google.gson.Gson
import okhttp3.Connection
import okhttp3.Interceptor
import okhttp3.Protocol
import okhttp3.Request
import okhttp3.Response
import java.net.URLDecoder

class KtHttpLogInterceptor(block: (KtHttpLogInterceptor.() -> Unit)? = null) : Interceptor {
    companion object {
        private const val TAG = "KtHttpLogInterceptor"
        private const val LOG_REQ_DIVIDED = "->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->"
        private const val LOG_RSP_DIVIDED = "<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-"
//        const val MILL
    }

    var mLogLevel: LogLevel = LogLevel.NONE
    var mColorLevel: ColorLevel = ColorLevel.DEBUG
    var mLogTag: String = TAG
    val mGson = Gson()

    init {
        Log.d("我被", "我被调用了")
        block?.invoke(this)
    }

    /**
     * 打印日至的范围
     */
    enum class LogLevel {
        NONE,   // 不打印
        BASIC,  // 只打印行首， 请求/响应
        HEADERS,// 打印请求和响应的 所有 header
        BODY,   // 打印所有
    }

    /**
     * Log 颜色等级，应用于Android Logcat分别为 v,d,i,w,e
     */
    enum class ColorLevel {
        VERBOSE,
        DEBUG,
        INFO,
        WARN,
        ERROR
    }

    override fun intercept(chain: Interceptor.Chain): Response {
        Log.d(TAG, "intercept: 好厉害的拦截器阿")
        val request = chain.request()
        return kotlin.runCatching { chain.proceed(request) }
            .onFailure {
                it.printStackTrace()
                logIt(it.message.toString(), ColorLevel.ERROR)
            }
            .onSuccess { response ->
                if (mLogLevel == LogLevel.NONE) {
                    return response
                }
                logRequest(request, chain.connection())
                logResponse(response)
            }
            .getOrThrow()
    }

    private fun logRequest(request: Request, connection: Connection?) {
        val sb = StringBuffer()
        sb.appendLine(LOG_REQ_DIVIDED)
        when (mLogLevel) {
            LogLevel.NONE -> {}
            LogLevel.BASIC -> {
                logBasicReq(sb, request, connection)
            }
            LogLevel.HEADERS -> {
                logHeadersReq(sb, request, connection)
            }
            LogLevel.BODY -> {
                logBodyReq(sb, request, connection)
            }
        }
        sb.appendLine(LOG_REQ_DIVIDED)
        logIt(sb)
    }

    private fun logBodyReq(
        sb: StringBuffer,
        request: Request,
        connection: Connection?
    ) {
        logHeadersReq(sb, request, connection)
        sb.appendLine("RequestBody: ${request.body}")
    }

    private fun logHeadersReq(
        sb: StringBuffer,
        request: Request,
        connection: Connection?
    ) {
        logBasicReq(sb, request, connection)
        val headersStr = request.headers.joinToString("") { header ->
            "请求 Header: {${header.first}=${header.second}}\n"
        }
        sb.appendLine(headersStr)
    }

    private fun logBasicReq(
        sb: StringBuffer,
        request: Request,
        connection: Connection?
    ) {
        sb.appendLine("请求 method: ${request.method} url: ${decodeUrlStr(request.url.toString())} tag:${request.tag()} protocol: ${connection?.protocol() ?: Protocol.HTTP_1_1}")
    }

    private fun logBodyRsp(
        sb:StringBuffer,
        response: Response,
    ){
        logHeadersRsp(sb, response)
        kotlin.runCatching {
            val peekBody = response.peekBody(1024 * 1024)
            sb.appendLine(peekBody.string())
        }.getOrNull()
    }
    private fun logHeadersRsp(
        sb:StringBuffer,
        response: Response,
    ){
        val headersStr = response.headers.joinToString("") { header ->
            "返回 Header: {${header.first}=${header.second}}\n"
        }
        sb.appendLine(headersStr)
        logBasicRsp(sb, response)
    }
    private fun logBasicRsp(
        sb:StringBuffer,
        response: Response,
    ){
        sb.appendLine()
    }


    private fun logResponse(response: Response){
        val sb = StringBuffer()
        sb.appendLine(LOG_RSP_DIVIDED)
        when (mLogLevel){
            LogLevel.NONE -> {}
            LogLevel.BASIC -> {
                logBasicRsp(sb, response)
            }
            LogLevel.HEADERS -> {
                logHeadersRsp(sb, response)
            }
            LogLevel.BODY -> {
                logBodyRsp(sb, response)
            }
        }
        sb.appendLine(LOG_RSP_DIVIDED)
        logIt(sb)
    }

    private fun decodeUrlStr(url: String): String? {
        return kotlin.runCatching {
            URLDecoder.decode(url, "utf-8")
        }.onFailure { it.printStackTrace() }.getOrNull()
    }

    private fun logIt(any: Any, tempLevel: ColorLevel? = null) {
        when (tempLevel ?: mColorLevel) {
            ColorLevel.VERBOSE -> Log.v(mLogTag, any.toString())
            ColorLevel.DEBUG -> Log.d(mLogTag, any.toString())
            ColorLevel.INFO -> Log.i(mLogTag, any.toString())
            ColorLevel.WARN -> Log.w(mLogTag, any.toString())
            ColorLevel.ERROR -> Log.e(mLogTag, any.toString())
        }
    }
}